﻿//---------------------------------------------------------------------------
// <copyright file="RibbonCommands.cs" company="Microsoft Corporation">
//     Copyright (C) Microsoft Corporation.  All rights reserved.
// </copyright>
//---------------------------------------------------------------------------

namespace Microsoft.Windows.Controls.Ribbon
{
    #region Using declarations

    using System;
    using System.ComponentModel;
    using System.Windows;
    using System.Windows.Input;
    using System.Windows.Media;

    #endregion Using declarations

    #region RibbonCommandAction Enum

    /// <summary>
    ///   The action being carried out by the RibbonCommand.
    /// </summary>
    public enum RibbonCommandAction
    {
        /// <summary>
        ///     Indicates that any enabled preview should be cancelled.
        /// </summary>
        CancelPreview,

        /// <summary>
        ///     Indicates that any enabled preview should be committed.
        /// </summary>
        CommitPreview,

        /// <summary>
        ///     Indicates that the preview behavior for the RibbonCommand should be enabled.
        /// </summary>
        Preview,
    }

    #endregion

    #region RibbonCommands Class

    /// <summary>
    ///   A static class containing a few stock RibbonCommands.
    /// </summary>
    public static class RibbonCommands
    {
        #region Fields

        /// <summary>
        ///   Backing store for the MaximizeWindow RibbonCommand property.
        /// </summary>
        private static RoutedCommand _maximizeWindowCommand;

        /// <summary>
        ///   Backing store for the MinimizeWindow RibbonCommand property.
        /// </summary>
        private static RoutedCommand _minimizeWindowCommand;

        /// <summary>
        ///   Backing store for the RestoreWindow RibbonCommand property.
        /// </summary>
        private static RoutedCommand _restoreWindowCommand;

        /// <summary>
        ///   Backing store for the CloseWindow RibbonCommand property.
        /// </summary>
        private static RoutedCommand _closeWindowCommand;

        /// <summary>
        ///   Backing store for the CustomizeQuickAcessToolbar RibbonCommand property.
        /// </summary>
        private static RoutedCommand _customizeQuickAccessToolbarCommand;

        #endregion

        #region Public Properties

        /// <summary>
        ///   Gets a RibbonCommand to maximize the Window.
        /// </summary>
        public static RoutedCommand MaximizeWindow
        {
            get { return _maximizeWindowCommand ?? (_maximizeWindowCommand = new RoutedCommand("MaximizeWindow", typeof(RibbonCommands))); }
        }

        /// <summary>
        ///   Gets a RibbonCommand to minimize the Window.
        /// </summary>
        public static RoutedCommand MinimizeWindow
        {
            get { return _minimizeWindowCommand ?? (_minimizeWindowCommand = new RoutedCommand("MinimizeWindow", typeof(RibbonCommands))); }
        }

        /// <summary>
        ///   Gets a RibbonCommand to restore the Window.
        /// </summary>
        public static RoutedCommand RestoreWindow
        {
            get { return _restoreWindowCommand ?? (_restoreWindowCommand = new RoutedCommand("RestoreWindow", typeof(RibbonCommands))); }
        }

        /// <summary>
        ///   Gets a RibbonCommand to close the Window.
        /// </summary>
        public static RoutedCommand CloseWindow
        {
            get { return _closeWindowCommand ?? (_closeWindowCommand = new RoutedCommand("CloseWindow", typeof(RibbonCommands))); }
        }

        /// <summary>
        ///   Gets a RibbonCommand to customize the QuickAccessToolbar.
        /// </summary>
        public static RoutedCommand CustomizeQuickAccessToolbar
        {
            get { return _customizeQuickAccessToolbarCommand ?? (_customizeQuickAccessToolbarCommand = new RoutedCommand("CustomizeQuickAcessToolbar", typeof(RibbonCommands))); }
        }

        #endregion
    }

    #endregion

    /// <summary>
    ///   The RibbonCommand class is the main store for RibbonControl metadata.  It
    ///   encapsulates display information like labels and icons with functional
    ///   information like CanExecute and Execute callbacks.
    /// </summary>
    public class RibbonCommand : RoutedCommand, INotifyPropertyChanged
    {
        #region Fields

        /// <summary>
        ///   Cached value for the CommandBinding associated with this RibbonCommand.
        /// </summary>
        private CommandBinding _commandBinding;

        /// <summary>
        ///   Backing store for the LargeImageSource property.
        /// </summary>
        private ImageSource _largeImageSource;

        /// <summary>
        ///   Backing store for the SmallImageSource property.
        /// </summary>
        private ImageSource _smallImageSource;

        /// <summary>
        ///   Backing store for the LabelTitle property.
        /// </summary>
        private string _labelTitle;

        /// <summary>
        ///   Backing store for the LabelDescription property.
        /// </summary>
        private string _labelDescription;

        /// <summary>
        ///   Backing store for the ToolTipTitle property.
        /// </summary>
        private string _toolTipTitle;

        /// <summary>
        ///   Backing store for the ToolTipDescription property.
        /// </summary>
        private string _toolTipDescription;

        /// <summary>
        ///   Backing store for the ToolTipImageSource property.
        /// </summary>
        private ImageSource _toolTipImageSource;

        /// <summary>
        ///   Backing store for the ToolTipFooterTitle property.
        /// </summary>
        private string _toolTipFooterTitle;

        /// <summary>
        ///   Backing store for the ToolTipFooterDescription property.
        /// </summary>
        private string _toolTipFooterDescription;

        /// <summary>
        ///   Backing store for the ToolTipFooterImageSource property.
        /// </summary>
        private ImageSource _toolTipFooterImageSource;

        /// <summary>
        ///   Cached value of the CanExecute handler.
        /// </summary>
        private CanExecuteRoutedEventHandler _canExecute;

        /// <summary>
        ///   Cached value of the Executed handler.
        /// </summary>
        private ExecutedRoutedEventHandler _executed;

        /// <summary>
        ///   Cached value of the PreviewCanExecute handler.
        /// </summary>
        private CanExecuteRoutedEventHandler _previewCanExecute;

        /// <summary>
        ///   Cached value of the PreviewExecute handler.
        /// </summary>
        private ExecutedRoutedEventHandler _previewExecuted;

        #endregion

        #region Constructors

        /// <summary>
        ///   Initializes a new instance of the RibbonCommand class.
        /// </summary>
        public RibbonCommand() :
            base()
        {
        }

        /// <summary>
        ///   Initializes a new instance of the RibbonCommand class.
        /// </summary>
        /// <param name="name">Declared name for serialization.</param>
        /// <param name="ownerType">The type which is registering the command.</param>
        public RibbonCommand(string name, Type ownerType) :
            base(name, ownerType, null)
        {
        }

        /// <summary>
        ///   Initializes a new instance of the RibbonCommand class.
        /// </summary>
        /// <param name="name">Declared name for serialization.</param>
        /// <param name="ownerType">The type which is registering the command.</param>
        /// <param name="inputGestures">Default input gestures associated with this command.</param>
        public RibbonCommand(string name, Type ownerType, InputGestureCollection inputGestures) :
            base(name, ownerType, inputGestures)
        {
        }

        #endregion

        #region Public Events

        /// <summary>
        ///     Called before the command is executed.
        /// </summary>
        public event ExecutedRoutedEventHandler PreviewExecuted
        {
            add
            {
                if (_commandBinding == null)
                {
                    _commandBinding = new CommandBinding(this, _executed, _canExecute);
                    CommandManager.RegisterClassCommandBinding(typeof(Window), _commandBinding);
                }

                _commandBinding.PreviewExecuted -= value;
                _commandBinding.PreviewExecuted += value;
                _previewExecuted = value;
            }

            remove
            {
                if (_commandBinding != null)
                {
                    _commandBinding.PreviewExecuted -= value;
                }

                _previewExecuted = null;
            }
        }

        /// <summary>
        ///     Called when the command is executed.
        /// </summary>
        public event ExecutedRoutedEventHandler Executed
        {
            add
            {
                if (_commandBinding == null)
                {
                    _commandBinding = new CommandBinding(this, value, _canExecute);
                    CommandManager.RegisterClassCommandBinding(typeof(Window), _commandBinding);
                }
                else
                {
                    _commandBinding.Executed -= value;
                    _commandBinding.Executed += value;
                }

                _executed = value;
            }

            remove
            {
                if (_commandBinding != null)
                {
                    _commandBinding.Executed -= value;
                }

                _executed = null;
            }
        }

        /// <summary>
        ///     Called before determining if the command can be executed.
        /// </summary>
        public event CanExecuteRoutedEventHandler PreviewCanExecute
        {
            add
            {
                if (_commandBinding == null)
                {
                    _commandBinding = new CommandBinding(this, _executed, _canExecute);
                    CommandManager.RegisterClassCommandBinding(typeof(Window), _commandBinding);
                }

                _commandBinding.PreviewCanExecute -= value;
                _commandBinding.PreviewCanExecute += value;
                _previewCanExecute = value;
            }

            remove
            {
                if (_commandBinding != null)
                {
                    _commandBinding.PreviewCanExecute -= value;
                }

                _previewCanExecute = null;
            }
        }

        /// <summary>
        ///     Called to determine if the command can be executed.
        /// </summary>
        public new event CanExecuteRoutedEventHandler CanExecute
        {
            add
            {
                if (_commandBinding == null)
                {
                    _commandBinding = new CommandBinding(this, _executed, value);
                    CommandManager.RegisterClassCommandBinding(typeof(Window), _commandBinding);
                }
                else
                {
                    _commandBinding.CanExecute -= value;
                    _commandBinding.CanExecute += value;
                }

                _canExecute = value;
            }

            remove
            {
                if (_commandBinding != null)
                {
                    _commandBinding.CanExecute -= value;
                }

                _canExecute = null;
            }
        }

        /// <summary>
        ///   This event is raised when a property of RibbonCommand changes.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region Public Properties

        /// <summary>
        ///   Gets or sets the LargeImageSource for this RibbonCommand.  At 96dpi this
        ///   is normally a 32x32 icon.
        /// </summary>
        public ImageSource LargeImageSource
        {
            get
            {
                return _largeImageSource;
            }

            set
            {
                if (value != _largeImageSource)
                {
                    _largeImageSource = value;
                    this.NotifyPropertyChanged("LargeImageSource");
                }
            }
        }

        /// <summary>
        ///   Gets or sets the SmallImageSource for this RibbonCommand.  At 96dpi this
        ///   is normally a 16x16 icon.
        /// </summary>
        public ImageSource SmallImageSource
        {
            get
            {
                return _smallImageSource;
            }

            set
            {
                if (value != _smallImageSource)
                {
                    _smallImageSource = value;
                    this.NotifyPropertyChanged("SmallImageSource");
                }
            }
        }

        /// <summary>
        ///   Gets or sets the LabelTitle for this RibbonCommand.  This is the primary
        ///   label that will be used on a bound Ribbon control.
        /// </summary>
        public string LabelTitle
        {
            get
            {
                return _labelTitle;
            }

            set
            {
                if (value != _labelTitle)
                {
                    _labelTitle = value;
                    this.NotifyPropertyChanged("LabelTitle");
                }
            }
        }

        /// <summary>
        ///   Gets or sets the LabelDescription for this RibbonCommand.
        /// </summary>
        public string LabelDescription
        {
            get
            {
                return _labelDescription;
            }

            set
            {
                if (value != _labelDescription)
                {
                    _labelDescription = value;
                    this.NotifyPropertyChanged("LabelDescription");
                }
            }
        }

        /// <summary>
        ///   Gets or sets the ToolTipTitle for this RibbonCommand.  This is
        ///   used as the main header of the ToolTip for a Ribbon control bound
        ///   to this RibbonCommand.
        /// </summary>
        public string ToolTipTitle
        {
            get
            {
                return _toolTipTitle;
            }

            set
            {
                if (value != _toolTipTitle)
                {
                    _toolTipTitle = value;
                    this.NotifyPropertyChanged("ToolTipTitle");
                }
            }
        }

        /// <summary>
        ///   Gets or sets the ToolTipDescription for this RibbonCommand.  This is
        ///   used as the main body description of the ToolTip for a Ribbon control
        ///   bound to this RibbonCommand.
        /// </summary>
        public string ToolTipDescription
        {
            get
            {
                return _toolTipDescription;
            }

            set
            {
                if (value != _toolTipDescription)
                {
                    _toolTipDescription = value;
                    this.NotifyPropertyChanged("ToolTipDescription");
                }
            }
        }

        /// <summary>
        ///   Gets or sets the ToolTipImageSource for this RibbonCommand.  This is
        ///   the main image in the body of the ToolTip for a Ribbon control bound
        ///   to this RibbonCommand.
        /// </summary>
        public ImageSource ToolTipImageSource
        {
            get
            {
                return _toolTipImageSource;
            }

            set
            {
                if (value != _toolTipImageSource)
                {
                    _toolTipImageSource = value;
                    this.NotifyPropertyChanged("ToolTipImageSource");
                }
            }
        }

        /// <summary>
        ///   Gets or sets the ToolTipFooterTitle for this RibbonCommand.  This is
        ///   the title of the footer of the ToolTip for a Ribbon control bound
        ///   to this RibbonCommand.
        /// </summary>
        public string ToolTipFooterTitle
        {
            get
            {
                return _toolTipFooterTitle;
            }

            set
            {
                if (value != _toolTipFooterTitle)
                {
                    _toolTipFooterTitle = value;
                    this.NotifyPropertyChanged("ToolTipFooterTitle");
                }
            }
        }

        /// <summary>
        ///   Gets or sets the ToolTipFooterDescription for this RibbonCommand.  This is
        ///   the main description in the footer of the ToolTip for a Ribbon control bound
        ///   to this RibbonCommand.
        /// </summary>
        public string ToolTipFooterDescription
        {
            get
            {
                return _toolTipFooterDescription;
            }

            set
            {
                if (value != _toolTipFooterDescription)
                {
                    _toolTipFooterDescription = value;
                    this.NotifyPropertyChanged("ToolTipFooterDescription");
                }
            }
        }

        /// <summary>
        ///   Gets or sets the ToolTipFooterImageSource for this RibbonCommand.  This is
        ///   the image used in the footer of the ToolTip for a Ribbon control bound to
        ///   this RibbonCommand.
        /// </summary>
        public ImageSource ToolTipFooterImageSource
        {
            get
            {
                return _toolTipFooterImageSource;
            }

            set
            {
                if (value != _toolTipFooterImageSource)
                {
                    _toolTipFooterImageSource = value;
                    this.NotifyPropertyChanged("ToolTipFooterImageSource");
                }
            }
        }

        #endregion

        #region Private Methods

        /// <summary>
        ///   Called to indicate that the indicated property has changed.
        /// </summary>
        /// <param name="info">The name of the property that changed.</param>
        private void NotifyPropertyChanged(string info)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }

        #endregion
    }

    #region RibbonCommandParameter Class

    /// <summary>
    ///   Encapsulates useful information for a RibbonCommand parameter.
    /// </summary>
    public class RibbonCommandParameter
    {
        #region Public Properties

        /// <summary>
        ///   Gets or sets the actual Command's parameter.
        /// </summary>
        public object CommandParameter
        {
            get;
            set;
        }

        /// <summary>
        ///   Gets or sets the RibbonCommandAction being carried out by the Command.
        /// </summary>
        public RibbonCommandAction Action
        {
            get;
            set;
        }

        /// <summary>
        ///   Gets or sets a parameter to the RibbonCommandAction.
        /// </summary>
        public object ActionParameter
        {
            get;
            set;
        }

        #endregion
    }

    #endregion

    #region CommandHelpers Class

    /// <summary>
    ///   A helper class for executing commands.   
    ///   TODO: Remove this once we merge into MS.Internal.
    /// </summary>
    internal static class CommandHelpers
    {
        /// <summary>
        ///   Executes the CommandSource's command as a RoutedCommand if possible,
        ///   otherwise as a regular Command.
        /// </summary>
        /// <param name="parameter">The parameter to the ICommandSource.</param>
        /// <param name="commandSource">The ICommandSource being executed.</param>
        internal static void ExecuteCommandSource(object parameter, ICommandSource commandSource)
        {
            ICommand command = commandSource.Command;
            if (command != null)
            {
                IInputElement target = commandSource.CommandTarget;

                RoutedCommand routed = command as RoutedCommand;
                if (routed != null)
                {
                    if (target == null)
                    {
                        target = commandSource as IInputElement;
                    }

                    if (routed.CanExecute(parameter, target))
                    {
                        routed.Execute(parameter, target);
                    }
                }
                else if (command.CanExecute(parameter))
                {
                    command.Execute(parameter);
                }
            }
        }
    }

    #endregion
}